#pragma once
#define WIN32_LEAN_AND_MEAN
#include <windows.h>

class TCriticalSection
{
public:
	TCriticalSection()
	{
		::InitializeCriticalSection( &mCriticalSection );
	}
	~TCriticalSection()
	{
		::DeleteCriticalSection( &mCriticalSection );
	}

	DWORD SetSpinCount( DWORD dwSpinCount = INFINITE )
	{
		return ::SetCriticalSectionSpinCount( &mCriticalSection, dwSpinCount );
	}
	BOOL TryEnter()
	{
		return ::TryEnterCriticalSection( &mCriticalSection );
	}
	VOID Leave()
	{
		::LeaveCriticalSection( &mCriticalSection );
	}

private:
	CRITICAL_SECTION mCriticalSection;
};

class TSyncObject
{
public:
	TSyncObject()
	{
		mhObject = NULL;
	}
	~TSyncObject()
	{
		if( mhObject )
		{
			::CloseHandle( mhObject );
			mhObject = NULL;
		}
	}

	virtual BOOL Lock( DWORD dwTimeOut = INFINITE )
	{
		if( mhObject == NULL )
			return FALSE;
		DWORD dwRet = ::WaitForSingleObject( mhObject, dwTimeOut );
		return ( WAIT_OBJECT_0 == dwRet );
	}
	virtual BOOL Unlock() = 0;

	operator HANDLE() const
	{
		return mhObject;
	}

protected:
	HANDLE mhObject;
};

class TEvent : public TSyncObject
{
public:
	BOOL Initialize( BOOL bManualReset, BOOL bInitialState, LPCTSTR lpName )
	{
		mhObject = ::CreateEvent( NULL, bManualReset, bInitialState, lpName );

		return ( mhObject != NULL );
	}
	BOOL Unlock()
	{
		return TRUE;
	}
	BOOL SetEvent()
	{
		return ::SetEvent( mhObject );
	}
	BOOL ResetEvent()
	{
		return ::ResetEvent( mhObject );
	}
};

class TMutex : public TSyncObject
{
public:
	BOOL Initialize( LPCTSTR lpName = NULL )
	{
		mhObject = ::CreateMutex( NULL, FALSE, lpName );

		return ( mhObject != NULL );
	}
	BOOL Unlock()
	{
		if( !::ReleaseMutex( mhObject ) )
		{
			// deal with error here
			return FALSE;
		}
		return TRUE;
	}
};

class TSemaphore : public TSyncObject
{
public:
	BOOL Initialize( LONG lInitialCount, LONG lMaximumCount, LPCTSTR lpName = NULL )
	{
		mhObject = ::CreateSemaphore( NULL, lInitialCount, lMaximumCount, lpName );

		return ( mhObject != NULL );
	}

	BOOL Unlock( LONG lCount, LPLONG lpPrevCount = NULL )
	{
		if( !::ReleaseSemaphore( mhObject, lCount, lpPrevCount ) )
		{
			// deal with error here
			return FALSE;
		}
		return TRUE;
	}

	BOOL Unlock()
	{
		return Unlock( 1, NULL );
	}
};
